/***********************************************************
 * $Id: NativeCodeInitialiser.java 384 2013-01-23 13:11:33Z tkistel $
 * Created: 21.01.2013
 *
 * (c) 2013 Technische Hochschule Wildau
 * (University of Applied Sciences Wildau)
 * All rights reserved
 ***********************************************************/
package de.thwildau.tm.moses.internal.netty.channel.rxtx;

import gnu.io.CommPortIdentifier;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Enumeration;
 

/**
 * A helper class to initialize the native code libraries from the RXTX bundle.
 *
 * @author Thomas Kistel
 * @version $Revision: 384 $
 */
public class NativeCodeInitialiser {
    
    static final String LIB_PATH_PROP = "java.library.path";
    static final String PROP_OS = "os.name";
    static final String PROP_ARCH = "os.arch";

    /**
     * Lookups the absolute path of the native libraries of the RXTX-Bundle and adds it to the library
     * path. The path of the library is identified depending on the System OS and ARCH.
     */
    public static void initNativeLibDirectory() {
        String libName = lookupLibraryPath();
        File libPath = null;
        try {
            ClassLoader cl = CommPortIdentifier.class.getClassLoader();
            Enumeration<URL> resources = cl.getResources(libName);
            while (resources.hasMoreElements()) {
                URL url = (URL)resources.nextElement();
                libPath = new File(url.toURI());
                System.out.println("adding to lib-path " + libPath.getAbsolutePath());
                addToLibraryPath(libPath.getAbsolutePath());
            }
        } catch (Exception e) {
            System.out.println("Could not add " + libPath != null ? libPath.getAbsolutePath() : libName + " to java library path, due to " + e.getClass().getName() + ": " + e.getMessage());
        }
    }
    
    /**
     * @see http://blog.cedarsoft.com/2010/11/setting-java-library-path-programmatically 
     */
    private static void addToLibraryPath(String path) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        String prop = System.getProperty(LIB_PATH_PROP);
        StringBuilder buf = new StringBuilder(prop);
        buf.append(File.pathSeparator);
        buf.append(path);
        System.setProperty(LIB_PATH_PROP, buf.toString());
        
        Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
        fieldSysPath.setAccessible( true );
        fieldSysPath.set( null, null );
    }
    
    // TODO improve this method by reading the /org.rxtx/META-INF/MANIFEST.MF file
    // and analyze the BundleNativeCode directive
    private static String lookupLibraryPath() {
        String osName = System.getProperty(PROP_OS).toLowerCase();
        String arch = System.getProperty(PROP_ARCH).toLowerCase();
        if(osName.contains("win")) {
            if(arch.contains("64"))
                return "lib/win64";
            return "lib/win32";
        } else if(osName.contains("linux") || osName.contains("unix")) {
            if(arch.contains("64"))
                return "lib/linux64";
            return "lib/linux32";
        } else
            return "lib/macosx";
    }
}
